package tech.yixiyun.framework.kuafu.view;

import tech.yixiyun.framework.kuafu.config.AppConfig;
import tech.yixiyun.framework.kuafu.config.ConfigKey;
import tech.yixiyun.framework.kuafu.controller.action.ActionContext;
import tech.yixiyun.framework.kuafu.controller.request.KuafuRequest;
import tech.yixiyun.framework.kuafu.controller.response.KuafuResponse;
import tech.yixiyun.framework.kuafu.kits.Kv;
import tech.yixiyun.framework.kuafu.service.Result;
import tech.yixiyun.framework.kuafu.service.State;
import tech.yixiyun.framework.kuafu.view.freemarker.FtlView;

import java.io.File;
import java.io.InputStream;

/**
 * 响应结果封装类，通过这个类的render()来生成响应结果。
 * 你需要自己去实现各种各种的View，可以参考框架提供的JSONView、JspView等等源码。<br/><br/>
 * 在View的子类实例里，你可以直接使用 request和response两个成员变量，你要做的就是实现render方法，
 * 在render方法中通过request或者response，决定返回给前端什么内容。<br/><br/>
 * <b>它在哪里用？Controller类的方法返回值类型，就是它！</b>
 * 只要Controller类方法的返回值类型是它，并且方法不是private修饰的，框架就会将这个方法识别为一个路由映射方法，
 * 根据类的基础路径和方法名，生成一个映射路径。更详细的路径生成规则，请看@Controller注解的注释说明
 */
public abstract class View {

    /**
     * 业务处理失败，如果是ajax请求，就返回{state:FAIL, msg:xxxx}，
     * 如果是其他请求，就跳到默认的500页面
     * @param msg
     * @return
     */
    public static View fail(String msg) {
        return fail(msg, null);
    }


    /**
     * 业务处理失败，如果是ajax请求，就返回{state:FAIL, msg:msg, data: data}，
     * 如果是其他请求，就跳到默认的500页面，同时会在request中绑定 msg和data
     * @param msg
     * @return
     */
    public static View fail(String msg, Object data) {
        if (ActionContext.getRequest().isAjaxRequest()) {
            return jsonFail(data, msg);
        }
        ActionContext.getRequest().setAttribute("msg", msg);
        ActionContext.getRequest().setAttribute("data", data);

        String errorPage = AppConfig.getAsString(ConfigKey.SERVER_ERRORPAGE_500);
        String contextPath = AppConfig.getAsString(ConfigKey.SERVER_CONTEXTPATH);
        boolean ends = contextPath.endsWith("/");
        if (ends && errorPage.startsWith("/")) {
            errorPage = contextPath + errorPage.substring(1);
        } else if (!ends && !errorPage.startsWith("/")) {
            errorPage = contextPath + "/" + errorPage;
        } else {
            errorPage = contextPath + errorPage;
        }
        return dispatch(errorPage);
    }


    /**
     * 构造一个跳转到jsp的view
     * @param path
     * @return
     */
    public static JspView jspView(String path) {
        if (path.startsWith("/") ==false) {
            path = "/" + path;
        }
        if (path.endsWith(".jsp") == false) {
            path += ".jsp";
        }
        return new JspView(path);
    }
    /**
     * 构造一个跳转到ftl的view
     * @param path
     * @return
     */
    public static FtlView ftlView(String path) {
        if (path.startsWith("/") ==false) {
            path = "/" + path;
        }
        if (path.endsWith(".ftl") == false) {
            path += ".ftl";
        }
        return new FtlView(path);
    }



    /**
     * 构造一个转向的view
     * @param path
     * @return
     */
    public static DispatchView dispatch(String path) {
        return new DispatchView(path);
    }

    /**
     * 构造一个重定向的view
     * @param path
     * @return
     */
    public static RedirectView redirect(String path) {
        return new RedirectView(path);
    }


    /**
     * 构造一个json格式字符串的view
     * @param data
     * @return
     */
    public static JSONView json(Object data) {
        return new JSONView(data);
    }
    /**
     * 构造一个json格式字符串的view
     * @param keyAndValues
     * @return
     */
    public static JSONView json(Object... keyAndValues) {
        return new JSONView(Kv.of(keyAndValues));
    }

    /**
     * 根据Result构建一个json格式字符串返回
     * @param result
     * @return
     */
    public static JSONView jsonResult(Result result) {
        return new JSONView(result);
    }

    /**
     * 返回一个代表请求成功的json格式字符串，内容是{state:"success"}
     * @return
     */
    public static JSONView jsonSuccess() {
        return jsonResult(new Result(State.SUCCESS));
    }

    /**
     * 返回一个代表请求成功的json格式字符串，内容是{state:"SUCCESS", data: xxxx}
     * @return
     */
    public static  View jsonSuccess(Object data) {
        return jsonResult(new Result(State.SUCCESS, data, null));
    }
    /**
     * 返回一个代表请求成功的json格式字符串，内容是{state:"SUCCESS", data: xxxx, msg:"xxx"}
     * @return
     */
    public static  View jsonSuccess(Object data, String msg) {
        return jsonResult(new Result(State.SUCCESS, data, msg));
    }

    /**
     * 返回一个代表请求失败的json格式字符串，内容是{state:"ERROR", msg:"xxxx"}
     * @return
     */
    public static  View jsonFail(String msg) {
        return jsonResult(new Result(State.FAIL,  msg));
    }
    /**
     * 返回一个代表请求失败的json格式字符串，内容是{state:"ERROR", msg:"xxxx", data: xxx}
     * @return
     */
    public static  View jsonFail(Object data, String msg) {
        return jsonResult(new Result(State.FAIL, data, msg));
    }

    /**
     * 返回一个代表请求警告的json格式字符串，内容是{state:"WARN", msg:"xxx"}
     * @return
     */
    public static  View jsonWarn(String msg) {
        return jsonResult(new Result(State.WARN, msg));
    }
    /**
     * 返回一个代表请求警告的json格式字符串，内容是{state:"WARN", msg:"xxx", data: xxx}
     * @return
     */
    public static  View jsonWarn(Object data, String msg) {
        return jsonResult(new Result(State.WARN, data, msg));
    }



    /**
     * 构造一个普通文本view
     * @param content
     * @return
     */
    public static TextView text(String content) {
        return new TextView(content);
    }

    /**
     * 输出一个下载文件流
     * @param fileName
     * @param bytes
     * @return
     */
    public static View download(String fileName, byte[] bytes) {
        return new StreamView(bytes,"content-disposition", "attachment;fileName="+fileName);
    }
    /**
     * 输出一个下载文件流
     * @param fileName
     * @param is
     * @return
     */
    public static View download(String fileName, InputStream is) {
        return new StreamView(is,"content-disposition", "attachment;fileName="+fileName);
    }
    /**
     * 输出一个下载文件流
     * @param fileName
     * @param file
     * @return
     */
    public static View download(String fileName, File file) {
        return new StreamView(file,"content-disposition", "attachment;fileName="+fileName);
    }
    /**
     * 输出一个下载文件流
     * @param fileName
     * @param path 路径，如果已/开头，就以绝对路径解析，否则就以相对项目webapp文件夹的路径去解析
     * @return
     */
    public static View download(String fileName, String path) {
        return new StreamView(fileName, "content-disposition", "attachment;fileName="+fileName);
    }

    /**
     * 输出一个图片流
     * @param is
     * @return
     */
    public static View image(InputStream is) {
        return new StreamView(is, "content-type","image/*", "Cache-Control", "no-cache","Pragma", "no-cache","expries", "-1");
    }

    /**
     * 输出一个图片流
     * @param bytes
     * @return
     */
    public static View image(byte[] bytes) {
        return new StreamView(bytes, "content-type","image/*","Cache-Control", "no-cache","Pragma", "no-cache","expries", "-1");
    }

    public KuafuRequest getRequest() {
        return ActionContext.getRequest();
    }

    public KuafuResponse getResponse() {
        return ActionContext.getResponse();
    }


    public View() {
    }



    /**
     * 当请求被正常处理后，要返回的响应
     */
    public abstract void render();




}
